package sys

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"gitee.com/gcom/gbox/errors"
	s "gitee.com/gcom/stockdock/core/support"
	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/pbkdf2"
)

type User struct {
	s.SimpleEntity
	Username string
	Password string
	Salt     string
	Role     string
}

func (User) TableName() string {
	return "sys_user"
}

var ErrPwdNotMatch = errors.New("密码错误")
var ErrNoSuchUser = errors.New("无此用户")

func Login(ctx s.TracerCtx, username, password string) (*User, error) {
	u, e := getUserBy(ctx, username)
	if e != nil {
		return nil, e
	}
	if u.Id == 0 {
		return nil, ErrNoSuchUser
	}
	if EncryptPassword(password, u.Salt) != u.Password {
		return nil, ErrPwdNotMatch
	}
	u.Password = ""
	u.Salt = ""
	return u, nil
}

func AddUser(ctx s.TracerCtx, username, password, role string) (*User, error) {
	salt := GenSalt(30)
	pwd := EncryptPassword(password, salt)
	u := &User{
		Username: username,
		Password: pwd,
		Salt:     salt,
		Role:     role,
	}
	err := ctx.DB.Create(u).Error
	if err != nil {
		err = errors.Wrap(err, "创建用户失败, "+err.Error())
	}
	return u, err
}

func GenSalt(len int) string {
	salt := make([]byte, len)
	_, err := rand.Read(salt)
	if err != nil {
		panic(err)
	}
	return base64.StdEncoding.EncodeToString(salt)
}

func EncryptPassword(pwd, salt string) string {
	return base64.StdEncoding.EncodeToString(pbkdf2.Key([]byte(pwd), []byte(salt), 20, 150, sha256.New))
}

func getUserBy(ctx s.TracerCtx, username string) (*User, error) {
	user := User{}
	db := ctx.DB.Model(&user).First(&user, "username = ?", username)
	err := db.Error
	if err == gorm.ErrRecordNotFound {
		err = nil
	}
	return &user, err
}

func updateUser(ctx s.TracerCtx, user *User) (int64, error) {
	db := ctx.DB.Save(user)
	return db.RowsAffected, db.Error
}
